package com.fintech.third.edczxutil.util;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.fintech.third.edczxutil.handle.TypeHandle;
import com.fintech.third.edczxutil.style.InitStyle;
import com.fintech.third.edczxutil.style.Style;
import com.fintech.third.edczxutil.style.StyleContext;
import com.fintech.third.edczxutil.style.StyleElement;
import com.fintech.third.edczxutil.style.StyleField;
import com.fintech.third.model.shzx.EdcZxPersonalInfo;
import com.marvels.common.utils.MarvelsLogUtil;

public class UtilXmlBean {
	
	static {
		//初始化 配置  xml报文跟javabean已经属性之间的关系，并且缓存起来
		try {
			InitStyle.init();
		} catch (Exception e) {
			MarvelsLogUtil.getInstance().error("初始化异常", e);
		}
	}
	
	public static void main(String[] args) throws Exception {
		Style style = StyleContext.getStyle("XinYongReport");//获取配置
		//反射实例化最外层的bean 也就是<title bean='...' />
		Object styleInstance= Class.forName(style.getBean()).newInstance();
		SAXReader saxReader = new SAXReader();
		//ClassLoader classLoader = Xml2bean.class.getClassLoader();
		URL url= UtilXmlBean.class.getResource("../util/zx.xml");
		//URL url= classLoader.getResource("zx.xml"); //TODO 用流
		Document douc= saxReader.read(new File(url.getFile()));
		Element root= douc.getRootElement();
		invokeElement(style.getElements(), root, styleInstance);
		EdcZxPersonalInfo report =(EdcZxPersonalInfo)styleInstance;
		MarvelsLogUtil.getInstance().info("styleInstance=" + styleInstance);
	}
	
	public static EdcZxPersonalInfo XmlUtilBean(Document douc){
		EdcZxPersonalInfo report = null;
		try {
			Style style = StyleContext.getStyle("XinYongReport");//获取配置
			//反射实例化最外层的bean 也就是<title bean='...' />
			Object styleInstance= Class.forName(style.getBean()).newInstance();
			SAXReader saxReader = new SAXReader();
			Element root= douc.getRootElement();
			invokeElement(style.getElements(), root, styleInstance);
			report = (EdcZxPersonalInfo)styleInstance;
		} catch (Exception e) {
			MarvelsLogUtil.getInstance().error("解析XML异常", e);
		} 
		return report;
	}
	
	/**
	 * 组装Field
	 * @param element
	 * @param xmlElement
	 * @param obj
	 * @throws Exception
	 */
	public static void invokeField(StyleElement element,Element xmlElement,Object obj) throws Exception{
		for (StyleField field : element.getFields()) {
			if(null!=xmlElement.element(field.getName())){
				Object value=xmlElement.element(field.getName()).getText();
				if(null!=field.getTypeHandle()&&null!=value){
					TypeHandle handle= field.getTypeHandle();
					value=handle.handle(value);
				}
				if(null!=field.getParent()){
					Object parent =invokeGetMethod(obj, "get"+captureName(field.getParent()));
					if(null==parent&&null!=field.getBean()){
						parent=Class.forName(field.getBean()).newInstance();
					}
					invokeSetMethod(parent, "set"+captureName(field.getValue()), Class.forName(field.getType()), value);
					invokeSetMethod(obj, "set"+captureName(field.getParent()), Class.forName(field.getBean()), parent);
				}else{
					invokeSetMethod(obj, "set"+captureName(field.getValue()), Class.forName(field.getType()), value);
				}
			}
		}
	}
	/**
	 * 组装Element
	 * @param elements style里配置的关系
	 * @param xmlElement 接口报文的Element对象
	 * @param obj 要放到哪个bean对象
	 * @throws Exception
	 */
	public static void invokeElement(List<StyleElement> elements,Element xmlElement,Object obj) throws Exception{
		for (StyleElement element : elements) {
			if("field".equals(element.getType())){
				if(null!=xmlElement.element(element.getTitle())){
					invokeField(element, xmlElement.element(element.getTitle()), obj);
				}
			}else if("list".equals(element.getType())){
				//如果是集合类型，根据报文的节点循环放到bean里
				List<Element> el = xmlElement.elements(element.getTitle());
				for (Element element2 : el) {
					Object eleInstance= Class.forName(element.getBean()).newInstance();
					for (StyleField field : element.getFields()) {
						Object value=element2.element(field.getName()).getText();
						if(null!=field.getTypeHandle()){
							TypeHandle handle= field.getTypeHandle();
							value=handle.handle(value);
						}
						invokeSetMethod(eleInstance, "set"+captureName(field.getValue()), Class.forName(field.getType()), value);
					}
					invokeSetMethod(obj, "add"+captureName(element.getValue()), Class.forName(element.getBean()), eleInstance);
				}
			}else{
				Object elementInstance =invokeGetMethod(obj, "get"+captureName(element.getValue()));
				if(null==elementInstance){
					elementInstance= Class.forName(element.getBean()).newInstance();
				}
				if(element.getElements()!=null && element.getElements().size()>0&&null!=xmlElement.element(element.getTitle())){
					//如果element里面有elements  递归解析、反射
					invokeElement(element.getElements(), xmlElement.element(element.getTitle()), elementInstance);
				}
				//element里面的filed属性，直接反射值到bean
				Element elem= xmlElement.element(element.getTitle());
				if(null!=element.getFields()&&null!=elem){
					invokeField(element, elem, elementInstance);
				}
				invokeSetMethod(obj, "set"+captureName(element.getValue()), Class.forName(element.getBean()), elementInstance);
				
			}
		}
	}
	
	/**
	 * 反射调用方法
	 * @param obj
	 * @param methodName
	 * @param methodTypes
	 * @param value
	 * @throws Exception
	 */
	public static void invokeSetMethod(Object obj,String methodName,Class<?> methodTypes,Object value) throws Exception{
		Method meehodElement= obj.getClass().getMethod(methodName, methodTypes);
		meehodElement.invoke(obj,value);
	}
	
	public static Object invokeGetMethod(Object obj,String methodName) throws Exception{
		Method meehodElement= obj.getClass().getMethod(methodName);
		return  meehodElement.invoke(obj);
	}
	
	/**
	 * 方法首字母大写
	 * @param name
	 * @return
	 */
	public static String captureName(String name) {
        char[] cs=name.toCharArray();
        cs[0]-=32;
        return String.valueOf(cs);
    }
}
